﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using IOA.MES.Log.Business;
using IOA.MES.Log.DataAccess.VModel;
using NLog;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace IOA.MES.Business
{
    /// <summary>
    /// 锁定管理（错误代码：143001）
    /// </summary>
    public class LockMgr
    {
        private MESContext mesDb = new MESContext("MES");
        private Logger logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 锁定组件
        /// </summary>
        /// <param name="barCodes">条码列表</param>
        /// <param name="lockReason">锁定原因</param>
        /// <param name="lockedBy">锁定人</param>
        public void Lock(List<string> barCodes, SiteType curSite, SiteType lockSite, int lockedBy, string lockReason)
        {
            barCodes = barCodes.Where(_ => !string.IsNullOrWhiteSpace(_)).Select(_ => _.ToUpper().Trim()).Distinct().ToList();
            if (!barCodes.Any())
            {
                return;
            }
            var components = mesDb.Components.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.Valid).ToList();
            components.ForEach(_ => _.BarCode = _.BarCode.ToUpper().Trim());

            if (barCodes.Any(_ => !components.Select(c => c.BarCode).Contains(_)))
            {
                throw new MultiLanBizException(138001, string.Join("、", barCodes.Where(_ => !components.Select(c => c.BarCode.ToUpper().Trim()).Contains(_))));//当前组件条码不存在
            }
            else if (components.Any(_ => !string.IsNullOrWhiteSpace(_.PackNo)))
            {
                throw new MultiLanBizException(138006, string.Join("、", components.Where(_ => !string.IsNullOrWhiteSpace(_.PackNo)).Select(_ => _.BarCode)));//下列组件已被打包，请解包后再试
            }

            components = components.Where(_ => !_.Locked).ToList();

            var entities = components.Select(_ => new LockRecord
            {
                OrderNo = _.OrderNo,
                WorkOrderNo = _.WorkOrderNo,
                ProductCode = _.ProductCode,
                ProductName = _.ProductName,
                ProductSpecs = _.ProductSpecs,
                WorkshopCode = _.WorkshopCode,
                WorkshopName = _.WorkshopName,
                LockedBy = lockedBy,
                LockedTime = DateTime.Now,
                LockedReason = lockReason,
                BarCode = _.BarCode,
                LockSite = lockSite,
                CurSite = curSite,
                CreateBy = lockedBy,
                CreateTime = DateTime.Now,
            }).ToList();
            mesDb.LockRecords.AddRange(entities);
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    foreach (var item in components)
                    {
                        var sql = $"UPDATE Component SET Locked = @Locked, LockedTime = @LockedTime, LockedBy = @LockedBy, LockedReason = @LockedReason, ModifyBy = @ModifyBy, ModifyTime = @ModifyTime WHERE BarCode = @BarCode";
                        var sqlParams = new List<SqlParameter>
                        {
                            new SqlParameter("@Locked", 1),
                            new SqlParameter("@LockedTime", DateTime.Now),
                            new SqlParameter("@LockedBy", lockedBy),
                            new SqlParameter("@LockedReason", lockReason),
                            new SqlParameter("@ModifyBy", lockedBy),
                            new SqlParameter("@ModifyTime", DateTime.Now),
                            new SqlParameter("@BarCode", item.BarCode),
                        };
                        mesDb.Database.ExecuteSqlCommand(sql, sqlParams.ToArray());
                    }

                    var user = new UserMgr().QueryUsers(new List<int> { lockedBy }).FirstOrDefault();
                    var logs = entities.Select(model => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = model.BarCode,
                        LogName = "组件锁定",
                        LogStatus = "异常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = "组件锁定",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"组件降级异常，组件条码：{string.Join(",", components.Select(_ => _.BarCode).ToList())}：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 解锁组件
        /// </summary>
        /// <param name="codes">条码列表</param>
        /// <param name="type">解锁方式(0：条码，1：箱号，2：柜号)</param>
        /// <param name="unLockReason">解锁说明</param>
        /// <param name="unLockedBy">解锁人</param>
        public void UnLock(List<string> codes, int type, string unLockReason, int unLockedBy)
        {
            codes = codes.Where(_ => !string.IsNullOrWhiteSpace(_)).Select(_ => _.ToUpper().Trim()).Distinct().ToList();
            if (!codes.Any())
            {
                return;
            }
            var components = new List<Component>();
            switch (type)
            {
                case 0:
                    components.AddRange(mesDb.Components.AsNoTracking().Where(_ => codes.Contains(_.BarCode) && _.Locked && _.Valid).ToList());
                    break;
                case 1:
                    components.AddRange(mesDb.Components.AsNoTracking().Where(_ => codes.Contains(_.PackNo) && _.Locked && _.Valid).ToList());
                    break;
                case 2:
                    components.AddRange(mesDb.Components.AsNoTracking().Where(_ => codes.Contains(_.CabinetNo) && _.Locked && _.Valid).ToList());
                    break;
            }
            if (!components.Any())
            {
                return;
            }

            var barCodes = components.Select(_ => _.BarCode.ToUpper().Trim()).Distinct().ToList();
            var locks = mesDb.LockRecords.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.UnLockedBy <= 0 && _.Valid).ToList();
            locks.ForEach(_ =>
            {
                mesDb.LockRecords.Attach(_);
                _.UnLockedBy = unLockedBy;
                _.UnLockedReason = unLockReason;
                _.UnLockedTime = DateTime.Now;
                _.ModifyBy = unLockedBy;
                _.ModifyTime = DateTime.Now;
            });
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                components.ForEach(_ =>
                {
                    mesDb.Components.Attach(_);
                    _.Locked = false;
                    _.LockedTime = null;
                    _.LockedBy = 0;
                    _.LockedReason = string.Empty;
                    _.ModifyBy = unLockedBy;
                    _.ModifyTime = DateTime.Now;
                    if (_.FinalInspectionTime.HasValue && string.IsNullOrWhiteSpace(_.QLevel))
                    {
                        _.QLevel = "Q1";
                        _.FinalInspectionOncePass = true;
                    }
                });
                mesDb.SaveChanges();

                var user = new UserMgr().QueryUsers(new List<int> { unLockedBy }).FirstOrDefault();
                var logs = components.Select(component => new VOprLog
                {
                    SubjectType = "组件",
                    SubjectNo = component.BarCode,
                    LogName = "组件解锁",
                    LogStatus = "正常",
                    OpeatorId = unLockedBy,
                    OpeatorName = user?.TrueName,
                    LogContent = "组件已解锁",
                    LogTime = DateTime.Now,
                    CreateBy = unLockedBy
                }).ToList();
                new OprLogMgr().AddLogs(logs);
            });
        }

        /// <summary>
        /// 查询锁定列表
        /// </summary>
        /// <param name="page">页面索引</param>
        /// <param name="limit">页面容量</param>
        /// <param name="total">总数量</param>
        /// <param name="workshopCode">车间代码</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="barCode">条码</param>
        /// <param name="startTime">开始创建时间</param>
        /// <param name="endTime">截止创建时间</param>
        /// <param name="unLocked">是否解锁</param>
        /// <returns>降级列表</returns>
        public List<VLockRecord> QueryLocks(int page, int limit, out int total, string workshopCode, string orderNo, string workOrderNo
            , string barCode, DateTime? startTime, DateTime? endTime, bool? unLocked)
        {
            var query = mesDb.LockRecords.AsNoTracking().Where(_ => _.Valid);
            if (!string.IsNullOrWhiteSpace(barCode))
            {
                query = query.Where(_ => _.BarCode == barCode);
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(workshopCode))
                {
                    query = query.Where(_ => _.WorkshopCode == workshopCode);
                }
                if (!string.IsNullOrWhiteSpace(orderNo))
                {
                    query = query.Where(_ => _.OrderNo == orderNo);
                }
                if (!string.IsNullOrWhiteSpace(workOrderNo))
                {
                    query = query.Where(_ => _.WorkOrderNo == workOrderNo);
                }

                if (startTime.HasValue)
                {
                    query = query.Where(_ => _.CreateTime >= startTime.Value);
                }
                if (endTime.HasValue)
                {
                    query = query.Where(_ => _.CreateTime <= endTime.Value);
                }
                if (unLocked == true)
                {
                    query = query.Where(_ => _.UnLockedBy > 0);
                }
                else if (unLocked == false)
                {
                    query = query.Where(_ => _.UnLockedBy <= 0);
                }
            }

            total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);

            var entities = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();

            var models = Mapper.Map<List<VLockRecord>>(entities);

            if (models.Any())
            {
                var userIds = models.Select(_ => _.LockedBy).ToList();
                userIds.AddRange(models.Select(_ => _.UnLockedBy));
                var users = new UserMgr().QueryUsers(userIds.Where(_ => _ > 0).Distinct().ToList());

                models.ForEach(model =>
                {
                    model.CNLockedBy = users.FirstOrDefault(_ => _.PkId == model.LockedBy)?.TrueName ?? string.Empty;
                    model.CNUnLockedBy = users.FirstOrDefault(_ => _.PkId == model.UnLockedBy)?.TrueName ?? string.Empty;
                });
            }

            return models;
        }
    }
}
